package com.qf.program.service.yjpy;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import org.apache.commons.lang3.StringUtils;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.util.*;


public class PublicUtils {


    // 截断数组取前八个
    public static <T> List<T> cutList(List<T> researchPointLs) {
        List<T> res;
        if (researchPointLs.size() > 9) {
            res = researchPointLs.subList(0, 9);
        } else {
            res = researchPointLs;
        }
        return res;
    }

    /**
     * 数据格式转换 非研究热点和新词发现
     *
     * @param researchPointLs       最后生成的数据
     * @param resultSubjectDatabase 类
     * @param type                  类型
     */
    public static void parseDataFormat(List<Res> researchPointLs, ResultSubjectDatabase resultSubjectDatabase, String type) {
        Res researchPoint = new Res();
        String hotKey = PublicUtils.backCommonKey(resultSubjectDatabase.getCi(), type);
        researchPoint.setFrontKey(hotKey);
        researchPoint.setScore(resultSubjectDatabase.getScore());
        String value = resultSubjectDatabase.getValue();
        if (type.equals("articleNum") || type.equals("articleCitationNum")) {
            if (type.equals("articleNum")) {

                if (!value.equals("[]")) {
                    List<Integer> jsonArray = JSONArray.parseArray(value, Integer.class);
                    researchPoint.setAids(jsonArray);
                    researchPoint.setCitationNum(jsonArray.size());
                }
                researchPointLs.add(researchPoint);
            } else {
                researchPoint.setCitationNum(resultSubjectDatabase.getPaperNum());
                researchPointLs.add(researchPoint);
            }
        } else if (type.equals("highAuthor") || type.equals("unit")) {
            if (type.equals("unit")) {
                ResearchFocus valueNei = JSON.parseObject(value, ResearchFocus.class);
                researchPoint.setAids(new ArrayList<>(valueNei.getIdList()));
                Res researchPointLs1 = parseToResJsonObjectNoHotKeySearch(valueNei, type);
                researchPoint.setSingleEntitys(researchPointLs1.getSingleEntitys());
                researchPointLs.add(researchPoint);
            } else {
                ResearchFocus valueNei = JSON.parseObject(value, ResearchFocus.class);
                researchPoint.setAids(new ArrayList<>(valueNei.getIdList()));
                Res researchPointLs1 = parseToResJsonObjectNoHotKeySearch(valueNei, type);
                researchPoint.setSingleEntitys(researchPointLs1.getSingleEntitys());
                researchPointLs.add(researchPoint);
            }

        } else if (type.equals("supportFund")) {
            ResearchFocus valueNei = JSON.parseObject(value, ResearchFocus.class);
            Res researchPointLs1 = parseToResJsonObjectNoHotKeySearch(valueNei, type);
            List<Res.SingleEntity> singleEntitys = researchPointLs1.getSingleEntitys();
            // 主要功能是把最外面的基金主题放在合作里面进行进来第一次可以进行加载
            Res.SingleEntity singleEntity = singleEntitys.get(0);
            List<Res.coWordMap> coWordMap = singleEntity.getCoWordMap();
            Res.coWordMap coWordMap1 = new Res.coWordMap();
            // researchPoint.setFrontKey(hotKey);
            //        researchPoint.setScore(resultSubjectDatabase.getScore());
            coWordMap1.setName(hotKey);
            coWordMap1.setScore(resultSubjectDatabase.getScore().intValue());
            coWordMap1.setAids(new ArrayList<>(valueNei.getIdList()));

            coWordMap.add(coWordMap1);
            List<Res.coWordMap> reverse = ListUtil.reverse(coWordMap);
            singleEntity.setCoWordMap(reverse);
            researchPoint.setSingleEntitys(researchPointLs1.getSingleEntitys());
            researchPointLs.add(researchPoint);
        } else {
            ResearchFocus valueNei = JSON.parseObject(value, ResearchFocus.class);
            Res researchPointLs1 = parseToResJsonObjectNoHotKeySearch(valueNei, type);
            researchPoint.setSingleEntitys(researchPointLs1.getSingleEntitys());
            researchPointLs.add(researchPoint);
        }

    }

    // 非研究热点和新词用
    public static Res parseToResJsonObjectNoHotKeySearch(ResearchFocus valueNei, String type) {
        Res res = new Res();
        res.setType(type);
        List<Res.SingleEntity> resSinle = new ArrayList<>();
//        String key = valueNei.getKey();
        Res.SingleEntity news = new Res.SingleEntity();
//        news.setName(key);
        news.setScore(valueNei.getScore());
        List<Res.coWordMap> coWordMap2 = news.getCoWordMap();
        Map<String, Set<Integer>> coWordMap = valueNei.getCoWordMap();
        for (Map.Entry<String, Set<Integer>> stringSetEntry : coWordMap.entrySet()) {
            Res.coWordMap coWordMap1 = new Res.coWordMap();
            coWordMap1.setName(stringSetEntry.getKey());
            coWordMap1.setScore(0);
            coWordMap1.setAids(new ArrayList<>(stringSetEntry.getValue()));
            coWordMap2.add(coWordMap1);
        }
        //  如果是基金 把最外层放在第一个

        news.setAids(valueNei.getIdList());
        resSinle.add(news);
        res.setSingleEntitys(resSinle);

        return res;
    }

    // 转换

    /**
     * 数据格式转换 研究热点和新词发现
     *
     * @param researchPointLs       最后生成的数据
     * @param resultSubjectDatabase 类
     * @param type                  类型
     */
    public static void parseDataFormatHotKeySearch(List<Res> researchPointLs, ResultSubjectDatabase resultSubjectDatabase, String type) {
        Res researchPoint = new Res();
        String hotKey = PublicUtils.backCommonKey(resultSubjectDatabase.getCi(), type);
        researchPoint.setFrontKey(hotKey);
        researchPoint.setScore(resultSubjectDatabase.getScore());
        String value = resultSubjectDatabase.getValue();
        Map<String, Object> listsMaps = JSON.parseObject(value, HashMap.class);
        Res researchPointLs1 = parseToResJsonObject(listsMaps, type);
        researchPoint.setSingleEntitys(researchPointLs1.getSingleEntitys());
        researchPointLs.add(researchPoint);
    }

    //jsonObject 模式
    public static Res parseToResJsonObject(Map<String, Object> param, String type) {
        Res res = new Res();
        res.setType(type);
        List<Res.SingleEntity> resSinle = new ArrayList<>();
        for (Map.Entry<String, Object> stringNewWordDiscoveryEntry : param.entrySet()) {
            String key = stringNewWordDiscoveryEntry.getKey();
            ResearchFocus value = JSON.parseObject(JSON.toJSONString(stringNewWordDiscoveryEntry.getValue()), ResearchFocus.class);
            Res.SingleEntity news = new Res.SingleEntity();
            news.setName(key);
            news.setScore(value.getScore());
            List<Res.coWordMap> coWordMap2 = news.getCoWordMap();
            Map<String, Set<Integer>> coWordMap = value.getCoWordMap();
            for (Map.Entry<String, Set<Integer>> stringSetEntry : coWordMap.entrySet()) {
                Res.coWordMap coWordMap1 = new Res.coWordMap();
                coWordMap1.setName(stringSetEntry.getKey());
                coWordMap1.setScore(0);
                coWordMap1.setAids(new ArrayList<>(stringSetEntry.getValue()));
                coWordMap2.add(coWordMap1);
            }
            news.setAids(value.getIdList());
            resSinle.add(news);
        }
        res.setSingleEntitys(resSinle);

        return res;
    }


    public static <T> List<T> cutList(List<T> researchPointLs, int size) {
        List<T> res;
        if (researchPointLs.size() > size) {
            res = researchPointLs.subList(0, size);
        } else {
            res = researchPointLs;
        }
        return res;
    }


    //删除拼音中的音调
    public static String rePy(String str) {
        return str.toLowerCase().replace("ā", "a").replace("à", "a").replace("á", "a").replace("ǎ", "a").replace("ě", "e").replace("é", "e").replace("ē", "e").replace("è", "e").replace("ī", "i").replace("ǐ", "i").replace("ì", "i").replace("í", "i").replace("ó", "o").replace("ō", "o").replace("ǒ", "o").replace("ò", "o").replace("ù", "u").replace("ǔ", "u").replace("ū", "u").replace("ú", "u").replace("ü", "u").replace("ǚ", "u").replace("ǜ", "u").replace("ǖ", "u").replace("ǘ", "u").replaceAll(" +", " ").trim();
    }


    // 自动判断文件的编码格式，这里要求必须为.txt结尾的文件。
    public static String codeString(String filePath) {
        String charset = "GBK";
        byte[] first3Bytes = new byte[3];
        try {
            boolean checked = false;
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
            bis.mark(0); // 读者注： bis.mark(0);修改为 bis.mark(100);我用过这段代码，需要修改上面标出的地方。
            // Wagsn注：不过暂时使用正常，遂不改之
            int read = bis.read(first3Bytes, 0, 3);
            if (read == -1) {
                bis.close();
                return charset; // 文件编码为 ANSI
            } else if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) {
                charset = "UTF-16LE"; // 文件编码为 Unicode
                checked = true;
            } else if (first3Bytes[0] == (byte) 0xFE && first3Bytes[1] == (byte) 0xFF) {
                charset = "UTF-16BE"; // 文件编码为 Unicode big endian
                checked = true;
            } else if (first3Bytes[0] == (byte) 0xEF && first3Bytes[1] == (byte) 0xBB && first3Bytes[2] == (byte) 0xBF) {
                charset = "UTF-8"; // 文件编码为 UTF-8
                checked = true;
            }
            bis.reset();
            if (!checked) {
                while ((read = bis.read()) != -1) {
                    if (read >= 0xF0) {
                        break;
                    }
                    if (0x80 <= read && read <= 0xBF) { // 单独出现BF以下的，也算是GBK
                        break;
                    }
                    if (0xC0 <= read && read <= 0xDF) {
                        read = bis.read();
                        if (0x80 <= read && read <= 0xBF) { // 双字节 (0xC0 - 0xDF)
                            // (0x80 - 0xBF),也可能在GB编码内
                            continue;
                        } else {
                            break;
                        }
                    } else if (0xE0 <= read && read <= 0xEF) { // 也有可能出错，但是几率较小
                        read = bis.read();
                        if (0x80 <= read && read <= 0xBF) {
                            read = bis.read();
                            if (0x80 <= read && read <= 0xBF) {
                                charset = "UTF-8";
                                break;
                            } else {
                                break;
                            }
                        } else {
                            break;
                        }
                    }
                }
            }
            bis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //SmallTool.printMess("--文件-> [" + path + "] 采用的字符集为: [" + charset + "]");
        return charset;
    }

    //获取百家姓
    public static Map<String, String> getBJX() {
        Map<String, String> map = new HashMap<>();
        map.put("薄", "bo");
        map.put("卜", "bu");
        map.put("曾", "zeng");
        map.put("查", "zha");
        map.put("仇", "qiu");
        map.put("单", "shan");
        map.put("都", "du");
        map.put("佴", "nai");
        map.put("皇甫", "huangpu");
        map.put("解", "xie");
        map.put("阚", "kan");
        map.put("乐", "yue");
        map.put("乐正", "yuezheng");
        map.put("缪", "miao");
        map.put("能", "nai");
        map.put("乜", "nie");
        map.put("拓跋", "tuoba");
        map.put("翟", "zhai");
        map.put("子车", "ziju");
        return map;
    }

    // 返回指定字段的值
    public static String getFieldValue(Entity entry, String field, Integer len) {
        String str = entry.getStr(field);
        if (null == str) {
            return "";
        }
        str = str.trim();
        if (str.length() > len) {
            return str;
        }
        return "";
    }

    // 插表，两个字段
    public static void insertTableTwo(String tableName, String fieldA, String valueA, String fieldB, String valueB) {
        try {
            Db.use().insert(Entity.create(tableName).set(fieldA, valueA).set(fieldB, valueB));
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    // 更新表，二个字段，key一般指的是自增主健，对应的一般就是id号，就是依自增主健进行更新。
    public static void updateTableTwo(String tableName, String fieldA, String valueA, String fieldB, String valueB, String key, Integer id) {
        try {
            Db.use().update(Entity.create().set(fieldA, valueA).set(fieldB, valueB), Entity.create(tableName).set(key, id));
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    // 对Map进行排序，此排序为最大的在前面，输入一个map，再返回一个排序后的新map，String, Double类型


    //获取两字符串的相似度_2 两字符串相似度计算算法 Levenshtein Distance编辑距离算法
    private static int compare(String str, String target) {
        int d[][];
        int n = str.length();
        int m = target.length();
        int i;
        int j;
        char ch1;
        char ch2;
        int temp;
        if (n == 0) {
            return m;
        }
        if (m == 0) {
            return n;
        }
        d = new int[n + 1][m + 1];
        for (i = 0; i <= n; i++) {
            d[i][0] = i;
        }
        for (j = 0; j <= m; j++) {
            d[0][j] = j;
        }
        for (i = 1; i <= n; i++) {
            ch1 = str.charAt(i - 1);
            for (j = 1; j <= m; j++) {
                ch2 = target.charAt(j - 1);
                if (ch1 == ch2 || ch1 == ch2 + 32 || ch1 + 32 == ch2) {
                    temp = 0;
                } else {
                    temp = 1;
                }
                d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + temp);
            }
        }
        return d[n][m];
    }

    //获取两字符串的相似度_3
    private static int min(int one, int two, int three) {
        return (one = one < two ? one : two) < three ? one : three;
    }

    //并查集算法String类型_1
    public static List<Set<String>> disjointSet(Set<String> set, String spl) {
        List<Set<String>> list = new ArrayList<>();
        List<String> vs = new ArrayList<>(set);
        int SIZE = vs.size();
        String[][] strs = new String[SIZE][];
        for (int i = 0; i < SIZE; i++) {
            strs[i] = vs.get(i).split(spl);
        }
        for (String[] str : strs) {
            Set<String> res = new HashSet<>(Arrays.asList(str));
            list.add(res);
        }
        int[] father = new int[SIZE];
        for (int i = 0; i < SIZE; i++) {
            father[i] = i;
        }
        Map<String, List<Integer>> map = new HashMap<>();
        for (int i = 0; i < SIZE; i++) {
            for (String each : strs[i]) {
                if (!map.containsKey(each)) {
                    List<Integer> li = new ArrayList<>();
                    li.add(i);
                    map.put(each, li);
                } else {
                    map.get(each).add(i);
                }
            }
        }
        for (Map.Entry<String, List<Integer>> entry : map.entrySet()) {
            List<Integer> value = entry.getValue();
            unionHelp(value, father);
        }
        for (int i = 0; i < SIZE; i++) {
            if (i != father[i]) {
                Set<String> dest = list.get(getFather(i, father));
                Set<String> source = list.get(i);
                dest.addAll(source);
            }
        }
        for (int i = 0; i < SIZE; i++) {
            if (i != father[i]) {
                list.get(i).clear();
            }
        }
        list.removeIf(strings -> strings.size() == 0);
        return list;
    }

    //并查集算法String类型_2
    public static void unionHelp(List<Integer> list, int[] father) {
        int minFather = getFather(list.get(0), father);
        for (int i = 0, size = list.size(); i < size; i++) {
            father[getFather(list.get(i), father)] = minFather;
        }
    }

    // 根据value 倒叙排列排序
    public static Map<Set<String>, Double> mapSortValueDouble(Map<Set<String>, Double> mapName) {
        Map<Set<String>, Double> result = new LinkedHashMap<>();
        mapName.entrySet().stream().sorted(Map.Entry.<Set<String>, Double>comparingByValue().reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        return result;
    }

    public static Map<String, Integer> mapSortValueInt(Map<String, Integer> mapName) {
        Map<String, Integer> result = new LinkedHashMap<>();
        mapName.entrySet().stream().sorted(Map.Entry.<String, Integer>comparingByValue().reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        return result;
    }

    // 返回map的第一个
    public static String mapSortValueIntReturnKey(Map<String, Integer> mapName) {
        Map<String, Integer> result = new LinkedHashMap<>();
        mapName.entrySet().stream().sorted(Map.Entry.<String, Integer>comparingByValue().reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        String res = "";
        for (Map.Entry<String, Integer> stringIntegerEntry : result.entrySet()) {
            String key = stringIntegerEntry.getKey();
            if (StringUtils.isNotEmpty(key)) {
                res = key;
                break;
            }
        }
        return res;
    }

    // 对Map进行排序，此排序为最大的在前面，输入一个map，再返回一个排序后的新map，String, Integer类型，本排序增加了过滤功能，可以设置要前多少（len）个。
    public static Map<String, List<Integer>> mapSortValueIntLen(Map<String, List<Integer>> mapName, Integer len) {
        Map<String, List<Integer>> ress = new LinkedHashMap<>();
        Map<String, Integer> mapNameRes = new LinkedHashMap<>();
        mapName.forEach((k,v)->{
            mapNameRes.put(k, v.size());
        });
        Map<String, Integer> result = new LinkedHashMap<>();
        mapNameRes.entrySet().stream()
                .sorted(Map.Entry.<String, Integer>comparingByValue()
                        .reversed()).limit(len).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        result.forEach((k,v)->{
            ress.put(k, mapName.get(k));
        });
        return ress;
    }


    /**
     * 2022年2月9日17:10:36 返回热词和部分新词公用的词语
     *
     * @param key
     * @param type 类型
     * @return
     */
    public static String backCommonKey(String key, String type) {
        String res = "";
//        String split = " ";
//        if (key.startsWith("[")) {
//            List<String> lists = JSON.parseArray(key, String.class);
//            Map<String, Integer> keySize = new ConcurrentHashMap<>();
//            if (lists.size() > 1) {
//                for (String list : lists) {
//                    String[] s = list.split(split);
//                    if (s.length == 2) {
//                        String k1 = s[0];
//                        String k2 = s[1];
//                        keySize.compute(k1, (k, v) -> {
//                            if (v == null) {
//                                v = 1;
//                            } else {
//                                v = v + 1;
//                            }
//                            return v;
//                        });
//                        keySize.compute(k2, (k, v) -> {
//                            if (v == null) {
//                                v = 1;
//                            } else {
//                                v = v + 1;
//                            }
//                            return v;
//                        });
//
//                    }
//                    if (s.length == 3) {
//                        String k1 = s[0] + split + s[1];
//                        String k2 = s[1] + split + s[2];
//                        keySize.compute(k1, (k, v) -> {
//                            if (v == null) {
//                                v = 1;
//                            } else {
//                                v = v + 1;
//                            }
//                            return v;
//                        });
//                        keySize.compute(k2, (k, v) -> {
//                            if (v == null) {
//                                v = 1;
//                            } else {
//                                v = v + 1;
//                            }
//                            return v;
//                        });
//
//
//                    }
//                    if (s.length == 4) {
//                        String k1 = s[0] + split + s[1] + split + s[2];
//                        String k2 = s[1] + split + s[2] + split + s[3];
//                        keySize.compute(k1, (k, v) -> {
//                            if (v == null) {
//                                v = 1;
//                            } else {
//                                v = v + 1;
//                            }
//                            return v;
//                        });
//                        keySize.compute(k2, (k, v) -> {
//                            if (v == null) {
//                                v = 1;
//                            } else {
//                                v = v + 1;
//                            }
//                            return v;
//                        });
//
//                    }
//
//                }
//                String integerIntegerMap = PublicUtils.mapSortValueIntReturnKey(keySize);
//                res = integerIntegerMap;
//            } else {
//                res = lists.get(0);
//            }
//        } else {
//            res = key;
//
//        }
        // 2022年2月10日09:35:53 老板给的新表 进行新表数据取
        if (type.equals("highAuthor")) {
//            List<String> aus = JSONArray.parseArray(key, String.class);
            res = key;
        } else {
            if (key.startsWith("{")) {
                CommonKey commonKey = JSON.parseObject(key, CommonKey.class);
                res = commonKey.getWord();
            } else {
                res = key;
            }
        }

        return res;
    }

    // 取小数点后4位
    public static double takeFourDigits(double d) {
        BigDecimal bd = new BigDecimal(d);
        BigDecimal bd2 = bd.setScale(4, RoundingMode.HALF_UP);
        return Double.parseDouble(bd2.toString());
    }

    //并查集算法String类型_3
    public static int getFather(int x, int[] father) {
        while (x != father[x]) {
            x = father[x];
        }
        return x;
    }


}
